세션으로 로그인 유지하기
✒️ 2025-05-26 11:08 내용 수정
실습 목표
- Session 객체를 사용하여 로그인을 하면 로그인 상태가 로그아웃 전까지 유지되는 페이지를 만든다.
실습 흐름
- 데이터베이스에 테이블 및 시퀀스, 필요 시 샘플 데이터 추가
- 데이터베이스에 연결 : context.xml 파일, 라이브러리(JDBC)
- 데이터베이스에서 회원 정보를 조회하는 DAO 클래스 생성
- 로그인을 위한 JSP 페이지 생성
- 로그인이 정상적으로 되었는지 확인하고, 로그인이 되었을 때만 메인 화면에 접근하도록 하는 중간 다리용 JSP 페이지 생성
- 로그인 후 접속 가능한 메인 화면용 JSP 생성
- 로그인 정보를 JSP로부터 전달 받아 데이터베이스와 비교하고 Session 객체를 추가하는 Servlet 생성
- 로그아웃 요청이 오면 Session을 제거하고 로그인 페이지로 보내는 Servlet 생성
DB에 테이블 추가
-- 시퀀스 생성
CREATE SEQUENCE SEQ_MEMBER_IDX;
--회원테이블
CREATE TABLE MEMBER(
IDX INT PRIMARY KEY, -- 번호
NAME VARCHAR2(100) NOT NULL, --이름
ID VARCHAR2(100) NOT NULL, --아이디
PWD VARCHAR2(100) NOT NULL, --비밀번호
EMAIL VARCHAR2(100) UNIQUE --이메일
);
--샘플 데이터 추가
INSERT INTO MEMBER VALUES(SEQ_MEMBER_IDX.nextVal,
'홍길동',
'aaa',
'1234',
'aaa@aaaa.com'
);
--커밋
COMMIT;
DB 연결
- context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource
auth="Container"
name="jdbc/oracle_test"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
factory="org.apache.commons.dbcp.BasicDataSourceFactory"
url="jdbc:oracle:thin:@localhost:1521:xe"
username="계정명" password="비밀번호"
maxActive="20" maxIdle="10" maxWait="1"/>
</Context>
- 라이브러리
| 파일 |
|---|
| commons-collections-3.2.1.jar |
| commons-dbcp-1.2.2.jar |
| commons-pool-1.4.jar |
| ojdbc8-23.3.0.23.09.jar |
| cos.jar |
- service용 DBService.java
package service;
import java.sql.Connection;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DBConnection {
static DBConnection db = null;
DataSource ds;
// singleton pattern으로 생성
public static DBConnection getInstance() {
if(db == null) {
db = new DBConnection();
}
return db;
}
// 생성자에서 Context 객체와 DataSource 초기화
public DBConnection() {
try {
InitialContext ic = new InitialContext();
Context ctx = (Context)ic.lookup("java:comp/env");
ds = (DataSource)ctx.lookup("jdbc/oracle_test");
} catch (NamingException e) {
e.printStackTrace();
}
}
// 생성자에서 준비한 정보로 DB에 연결하여 Connection 객체 얻기
public Connection getConnection() {
Connection connec = null;
try {
connec = ds.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return connec;
}
}
Ajax
- HttpRequest.js
var xhr = null;
function createRequest() {
if (xhr != null) {
return;
}
if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHTTP"); // IE 환경
} else {
xhr = new XMLHttpRequest(); // 기타 브라우저 환경
}
}
function sendRequest(url, param, callback, method) {
// HttpRequest 생성
createRequest();
// 전송 타입 구분
var httpMethod = (method != 'POST' && method != 'post') ? 'GET' : 'POST';
// 파라미터 구분
var httpParam = (param == null || param == '') ? null : param;
// 접근 url
var httpURL = url;
// 요청 방식이 GET이고 전달할 파라미터가 있다면 새 url 경로 제작
if (httpMethod == 'GET' && httpParam != null) {
httpURL = httpURL+'?'+httParam;
}
// 서버로 보낼 Ajax 요청 형식
xhr.open(httpMethod, httpURL, true);
// requestHeader 설정 : Content-Type 지정
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 작업이 완료된 후 호출할 callback 메소드 지정
xhr.onreadystatechange = callback;
// Ajax 요청을 서버로 전달
xhr.send(httpMethod == 'POST' ? httpParam : null);
}
DTO와 DAO
- dto
package dto;
import lombok.Data;
@Data
public class MemberDTO {
private String name, id, pwd;
}
- dao
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import dto.MemberDTO;
import service.DBService;
public class MemberDAO {
// single-ton pattern:
static MemberDAO single = null;
public static MemberDAO getInstance() {
if (single == null)
single = new MemberDAO();
return single;
}
public MemberDTO selectOne(String id) {
MemberDTO dto = null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "SELECT * FROM MEMBER WHERE ID=?";
try {
//1.Connection얻어온다
conn = DBService.getInstance().getConnection();
//2.명령처리객체정보를 얻어오기
pstmt = conn.prepareStatement(sql);
//3.pstmt parameter 설정
pstmt.setString(1, id);
//4.결과행 처리객체 얻어오기
rs = pstmt.executeQuery();
if (rs.next()) {
dto = new MemberDTO();
dto.setPwd(rs.getString("pwd"));
dto.setName(rs.getString("name"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return dto;
}
}
Servlet
- 로그인 Servlet
package action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import dao.MemberDAO;
import dto.MemberDTO;
@WebServlet("/login")
public class LoginAction extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String id = request.getParameter("id");
String pwd = request.getParameter("pwd");
MemberDTO dto = MemberDAO.getInstance().selectOne(id);
String param = "";
String resultStr = "";
// dto가 null일 경우 id가 DB 자체에 존재하지 않음
if(dto == null) {
param = "no_id";
resultStr = String.format("[{'param':'%s'}]", param);
response.getWriter().print(resultStr);
return;
}
if(!pwd.equals(dto.getPwd())) {
param = "no_pwd";
resultStr = String.format("[{'param':'%s'}]", param);
response.getWriter().print(resultStr);
return;
}
// 아이디와 비밀번호 체크에 문제가 없다면 세션에 바인딩함
// 세션은 서버의 메모리를 사용하기 때문에 세션을 많이 사용할수록 브라우저가
// 느려지기 때문에 필요한 곳에서만 사용해야 함
HttpSession session = request.getSession();
session.setAttribute("dto", dto); // 포워딩 필요 없이 JSP에서 el 표기법으로 접근 가능
// 로그인 성공한 경우
param = "clear";
resultStr = String.format("[{'param':'%s'}]", param);
response.getWriter().print(resultStr);
}
}
- 로그아웃 Servlet
package action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet("/logout")
public class LogoutAction extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Session을 제거
HttpSession session = request.getSession();
session.removeAttribute("dto");
response.sendRedirect("login_form.jsp");
}
}
JSP
- 로그인 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="js/HttpRequest.js"></script>
<script>
function send(f) {
var id = f.id.value.trim();
var pwd = f.pwd.value.trim();
// 유효성 검사
if (id == '') {
alert("아이디를 입력해주세요");
return;
}
if (pwd == '') {
alert("비밀번호를 입력해주세요");
return;
}
var url = "login";
var param = "id="+id+"&pwd="+encodeURIComponent(pwd);
sendRequest(url, param, myCheck, "POST");
}
function myCheck() {
if (xhr.readyState == 4 && xhr.status == 200) {
var data = xhr.responseText;
var json = eval(data);
if(json[0].param == "no_id") {
alert("아이디가 존재하지 않습니다.");
} else if (json[0].param == "no_pwd") {
alert("비밀번호가 일치하지 않습니다.");
} else if (json[0].param == "clear") {
alert("로그인에 성공했습니다.");
location.href = "main_content.jsp";
}
}
}
</script>
</head>
<body>
<form>
<table border="1" align="center">
<caption>:::로그인:::</caption>
<tr>
<th>아이디</th>
<td><input name="id"></td>
</tr>
<tr>
<th>비밀번호</th>
<td><input name="pwd" type="password"></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" value="로그인" onclick="send(this.form)">
</td>
</tr>
</table>
</form>
</body>
</html>
- 로그인 확인용 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${empty dto}">
<script>
alert('로그인 후 이용해주세요');
location.href='login_form.jsp';
</script>
</c:if>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
</body>
</html>
- 로그인 후 메인 화면 jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- check_login.jsp를 거쳐서 나오도록 설정 -->
<jsp:include page="check_login.jsp"/> <br>
메인페이지 <br>
${dto.name}님 로그인을 환영합니다.
<input type="button" value="로그아웃" onclick="location.href='logout'">
</body>
</html>
완성된 모습
-
아이디를 입력한다.
-
DB에 존재하지 않는 아이디라면 아이디가 없다고 뜬다.
-
아이디는 일치하는데 비밀번호가 일치하지 않으면 비밀번호 불일치로 뜬다.
-
아이디와 비밀번호가 모두 맞으면 로그인 성공 메시지가 뜬다.
-
로그인 체크 화면을 거쳐 메인 화면으로 온다.
-
로그아웃을 했거나 로그인을 안 한 상태로 URL을 변경하여 main_content.jsp에 접근하려고 하면 접근이 막힌다.